// Trait Object Tests for NRC
// --------------------------
// 本文件是 Trait 对象 (&Trait / Rc<Trait> / Weak<Trait>) 的集成测试。
// 当前编译器已经支持首版 Trait 对象实现，本文件中的测试应全部通过。

// 1. 定义一个基础 Trait：Animal
//    所有实现 Animal 的类型都需要提供 make_sound 方法。
type Animal trait {
    func make_sound() String
}

// 2. 两个具体类型：Dog 和 Cat
type Dog struct {
    name String
}

type Cat struct {
    name String
}

// 3. 为 Dog / Cat 实现 Animal Trait
impl Animal for Dog {
    func make_sound() String {
        return "Dog " + self.name + " says: Woof!"
    }
}

impl Animal for Cat {
    func make_sound() String {
        return "Cat " + self.name + " says: Meow!"
    }
}

// 4. 接受 Trait 对象参数的函数
//    语法：&Animal
//    语义：接受“任意实现了 Animal 的对象的引用”，通过 vtable 做动态分发。
func print_sound(animal &Animal) {
    // 未来语义：这里的 animal.make_sound() 会根据实际类型
    // (Dog / Cat / 其他 Animal 实现) 做运行时多态调用。
    var sound String = animal.make_sound()
    println(sound)
    // 断言：Trait 对象调用返回的字符串非空
    assert(!sound.is_empty(), "Animal sound should not be empty")
}

// 5. 基础用法：把具体类型通过 &Animal 传入
func test_trait_object_basic() {
    println("=== Trait Object Basic Demo ===")

    var dog Dog = Dog{
        name: "Buddy",
    }
    var cat Cat = Cat{
        name: "Kitty",
    }

    // 基础断言：直接调用具体类型的方法
    var dog_sound String = dog.make_sound()
    var cat_sound String = cat.make_sound()
    println("dog_sound: ", dog_sound)
    println("cat_sound: ", cat_sound)
    assert(dog_sound == "Dog Buddy says: Woof!", "Dog make_sound() should match expected text")
    assert(cat_sound == "Cat Kitty says: Meow!", "Cat make_sound() should match expected text")

    // 语法意图：&Dog / &Cat 自动“提升”为 &Animal
    print_sound(&dog)
    print_sound(&cat)

    // 通过 Trait 引用调用，行为应与具体类型一致
    var a1 &Animal = &dog
    var a2 &Animal = &cat
    assert(a1.make_sound() == dog_sound, "Trait reference for Dog should dispatch to Dog implementation")
    assert(a2.make_sound() == cat_sound, "Trait reference for Cat should dispatch to Cat implementation")
}

// 6. 异构集合：Vec<Rc<Animal>>
//    一个 Vec 里同时存放 Dog / Cat 等不同具体类型，
//    但统一以 Rc<Animal> 的抽象视图操作。
func test_trait_object_collection() {
    println("=== Trait Object Vec<Rc<Animal>> Demo ===")

    var dog Dog = Dog{
        name: "Buddy",
    }
    var cat Cat = Cat{
        name: "Kitty",
    }

    // 计划中的类型写法：Vec<Rc<Animal>>
    var animals Vec<Rc<Animal> > = Vec<Rc<Animal> >{}
    animals.push(Rc<Animal>{dog})
    animals.push(Rc<Animal>{cat})

    var count int = 0
    var saw_dog bool = false
    var saw_cat bool = false

    // 计划中的 for-in 写法：for var a Rc<Animal> in animals { ... }
    for var a Rc<Animal> in animals {
        var s String = a.make_sound()
        println(s)
        if s == "Dog Buddy says: Woof!" {
            saw_dog = true
        }
        if s == "Cat Kitty says: Meow!" {
            saw_cat = true
        }
        count = count + 1
    }

    assert(animals.len() == 2, "Vec<Rc<Animal>> length should be 2")
    assert(count == 2, "Vec<Rc<Animal>> should iterate over two elements")
    assert(saw_dog, "Vec<Rc<Animal>> should contain Dog element")
    assert(saw_cat, "Vec<Rc<Animal>> should contain Cat element")
}

// 7. （可选）返回 Rc<Animal> 的工厂函数
//    注意：这里演示的是“返回拥有所有权的 Trait 对象（Rc<Animal>）”，
//    与 NRC 中“要么值传递，要么 Rc”的设计保持一致。
func pick_louder(dog Dog, cat Dog) Rc<Animal> {
    // 假设我们以后有更复杂的逻辑，这里先写死返回第一个参数。
    // 这里的参数类型也可以按需改成 Animal 的不同实现类型。
    return Rc<Animal>{dog}
}

func test_trait_object_return() {
    println("=== Trait Object Return Rc<Animal> Demo ===")

    var dog Dog = Dog{
        name: "Buddy",
    }
    var dog2 Dog = Dog{
        name: "Max",
    }

    var louder Rc<Animal> = pick_louder(dog, dog2)
    var louder_sound String = louder.make_sound()
    println("Louder animal says: ", louder_sound)

    // 这里我们约定 pick_louder 始终基于第一个参数构造 Rc<Animal>
    assert(louder_sound == dog.make_sound(), "pick_louder should currently return Rc<Animal> wrapping the first Dog")
}

func test_trait_object_rc_weak_flow() {
    println("=== Trait Object Rc->Weak->lock Demo ===")

    var dog Dog = Dog{
        name: "Charlie",
    }

    var rc_animal Rc<Animal> = Rc<Animal>{dog}
    var weak Weak<Animal> = rc_animal.downgrade()
    var locked Option<Rc<Animal> > = weak.lock()
    assert(locked.is_some(), "downgrade/lock should succeed while Rc is alive")

    var locked_rc Rc<Animal> = locked.unwrap()
    assert(
        locked_rc.make_sound() == rc_animal.make_sound(),
        "Locked Rc<Animal> should produce same sound as original",
    )
}

func test_trait_object_weak_lock_default() {
    var weak Weak<Animal>
    var locked Option<Rc<Animal> > = weak.lock()
    assert(locked.is_none(), "Default Weak<Animal> should lock to None")
}

